/*-
 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
 * Redistribution and modifications are permitted subject to BSD license.
 */
#include <asn_SET_OF.h>
#include <asn_internal.h>
#include <errno.h>

/*
 * Add another element into the set.
 */
int asn_set_add(void* asn_set_of_x, void* ptr) {
  asn_anonymous_set_* as = _A_SET_FROM_VOID(asn_set_of_x);

  if (as == 0 || ptr == 0) {
    errno = EINVAL; /* Invalid arguments */
    return -1;
  }

  /*
   * Make sure there's enough space to insert an element.
   */
  if (as->count == as->size) {
    int _newsize = as->size ? (as->size << 1) : 4;
    void* _new_arr;
    _new_arr = REALLOC(as->array, _newsize * sizeof(as->array[0]));
    if (_new_arr) {
      as->array = (void**) _new_arr;
      as->size  = _newsize;
    } else {
      /* ENOMEM */
      return -1;
    }
  }

  as->array[as->count++] = ptr;

  return 0;
}

void asn_set_del(void* asn_set_of_x, int number, int _do_free) {
  asn_anonymous_set_* as = _A_SET_FROM_VOID(asn_set_of_x);

  if (as) {
    void* ptr;
    if (number < 0 || number >= as->count) return;

    if (_do_free && as->free) {
      ptr = as->array[number];
    } else {
      ptr = 0;
    }

    as->array[number] = as->array[--as->count];

    /*
     * Invoke the third-party function only when the state
     * of the parent structure is consistent.
     */
    if (ptr) as->free(ptr);
  }
}

/*
 * Free the contents of the set, do not free the set itself.
 */
void asn_set_empty(void* asn_set_of_x) {
  asn_anonymous_set_* as = _A_SET_FROM_VOID(asn_set_of_x);

  if (as) {
    if (as->array) {
      if (as->free) {
        while (as->count--) as->free(as->array[as->count]);
      }
      FREEMEM(as->array);
      as->array = 0;
    }
    as->count = 0;
    as->size  = 0;
  }
}
